﻿unit oPathsManager;

{
	created   8.3.2010
	author    Miroslav Mintal
	purpose   holds and manages the Paths Types

	edit list:
}

interface

uses
  oManager, Classes, Generics.Collections, oProcessItem, SysUtils,
  XMLDoc, XMLIntf, oEntity, oProcessObjects, oEntityTypeConstants;

type
  EPathsManager = class(Exception)
  end;

  ENotValidPathsType = class(EPathsManager)
  end;

  EPathNotExists = class(EPathsManager)
  end;

  EPathBadSpawnSink = class(EPathsManager)
  end;

  TPathsManager = class(TManager)
    public
      type
//        fMatrix = array of array of integer;
        TPathType = class(TProcessable)
          strict private
            aName: String;
            aMaster: TManager;
            aWayPoints: Tlist<TEntity>;
            aWayMatrixes : TList<fMatrix>;
          public
            property Name: String read aName;
            property WayPoints: Tlist<TEntity> read aWayPoints;
            property WayMatrixes: TList<fMatrix> read aWayMatrixes;
            destructor Destroy; override;
          private
            constructor Create(paName: String; paMaster: TManager);
            function Insert(paNew: TEntity; paBefore:TEntity = nil):Boolean;
            function Remove(paRemove: TEntity):Boolean;
            procedure Save(paWhere: IXMLNode);
            procedure Load(paFrom: IXMLNode);
            procedure resetList;
        end;
    private
      aPaths: TList<TPathType>;
      function search(paName: String): TPathType;
//      function exists(paName: String): boolean;
      procedure CheckSpawnSink;
    public
      property Paths: TList<TPathType> read aPaths;
      constructor Create(paMaster: TManager);
      destructor Destroy; override;
      procedure resetList;
      function ProcessObject(paItem: TProcessItem):TProcessItem; override; final;
      procedure Save(var paWhere: IXMLNode);
      procedure Load(paFrom: IXMLNode);
  end;

implementation

uses
  oProcessObjectConstants;

resourcestring ePathManNotValidType = 'not a valid processing type';
resourcestring ePathManNotValidConstant = 'not a valid constant';
resourcestring ePathManEntityNotFound = 'entity not found';
resourcestring ePathManPathNotFound = 'path not found';
resourcestring ePathManBadSpawn = 'path must start with spawn';
resourcestring ePathManBadSink = 'path must end with sink';

{ TPedestrianManager }

procedure TPathsManager.CheckSpawnSink;
var
  path: TPathType;
begin
  for path in Paths do
  begin
    if (path.WayPoints.Count >= 1) then
    begin
      if (path.WayPoints.Items[0].TypeLogic <> ET_SPAWN_TYPE) then
        raise EPathBadSpawnSink.Create(ePathManBadSpawn);
      if (path.WayPoints.Count >= 2) then
      begin
        if (path.WayPoints.Items[path.WayPoints.Count-1].TypeLogic <> ET_SINK_TYPE) then
          raise EPathBadSpawnSink.Create(ePathManBadSink);
      end;
    end;
  end;
end;

constructor TPathsManager.Create(paMaster: TManager);
begin
  aMaster := paMaster;
  aPaths := TList<TPathType>.Create;
end;

destructor TPathsManager.Destroy;
var
  path: TPathType;
begin
  for path in Paths do
    path.Free;
  aPaths.Free;
  inherited;
end;

{
function TPathsManager.exists(paName: String): boolean;
var
  path: TPathType;
begin
  result := false;
  for path in Paths do
    if path.Name = paName then
    begin
      result := true;
      break;
    end;
end;
}

function TPathsManager.ProcessObject(paItem: TProcessItem): TProcessItem;
var
  s: TString;
  path: TPathType;
  e1, e2: TEntityProcessing;
  e01, e02: TEntity;
  list: TProcessingList;
  node: IXMLNode;
  strings : TStringList;
begin
  result := nil;

  case paItem.Code of

    PO_PATHS_UNLOAD:
    begin
      resetList;
    end;

    PO_PATHS_INSERT_PATH:
    begin
      try
        if not(paItem.Data is TString) then raise ENotValidPathsType.Create(ePathManNotValidType);
        if search((paItem.Data as TString).String_) = nil then
        begin
          Paths.Add(TPathType.Create((paItem.Data as TString).String_, aMaster));
          result := TProcessItem.create(PO_SUCCESS,nil);
        end
        else
          result := TProcessItem.create(PO_FAILURE,nil);
      except
        on E:ENotValidPathsType do raise EPathsManager.Create(ePathManNotValidType);
        on E:EPathsManager do result := TProcessItem.create(PO_FAILURE,nil);
      end;
    end;

    PO_PATHS_REMOVE_PATH:
    begin
      try
        if not(paItem.Data is TString) then raise ENotValidPathsType.Create(ePathManNotValidType);
        aPaths.Remove(search((paItem.Data as TString).String_));
        aMaster.ProcessObject(TProcessItem.create(PO_PROJECT_SAVE_PATHS, NIL));
      except
        on E:ENotValidPathsType do raise EPathsManager.Create(ePathManNotValidType);
        on E:EPathsManager do result := TProcessItem.create(PO_FAILURE,nil);
      end;
    end;

    PO_PATHS_INSERT_WAYPOINT:
    begin
      try
        if not(paItem.Data is TProcessingList) then raise ENotValidPathsType.Create(ePathManNotValidType);
        list := (paItem.Data as TProcessingList);
        s := list.Parameters[0];
        e1 := list.Parameters[1];
        e01 := e1.Entity_;
        e2 := list.Parameters[2];
        e02 := nil;
        if e2 <> nil then
          e02 := e2.Entity_;
        if (search(s.String_).Insert(e01, e02))
        then
          result := TProcessItem.create(PO_SUCCESS,nil)
        else
          result := TProcessItem.create(PO_FAILURE,nil);
      except
        on E:ENotValidPathsType do raise EPathsManager.Create(ePathManNotValidType);
        on E:EPathsManager do result := TProcessItem.create(PO_FAILURE,nil);
      end;
    end;

    PO_PATHS_REMOVE_WAYPOINT:
    begin
      try
        if not(paItem.Data is TProcessingList) then raise ENotValidPathsType.Create(ePathManNotValidType);
        list := (paItem.Data as TProcessingList);
        s := list.Parameters[0];
        e1 := list.Parameters[1];
        if (search(s.String_).Remove(e1.Entity_))        then
          result := TProcessItem.create(PO_SUCCESS,nil)
        else
          result := TProcessItem.create(PO_FAILURE,nil);      except
        on E:ENotValidPathsType do raise EPathsManager.Create(ePathManNotValidType);
        on E:EPathsManager do result := TProcessItem.create(PO_FAILURE,nil);
      end;
    end;

    PO_PATHS_SAVE:
    begin
      try
        if not(paItem.Data is TProcessingXML) then raise ENotValidPathsType.Create(ePathManNotValidType);
        node := ((paItem.Data) as TProcessingXML).Node;
        // CheckSpawnSink;
        Save(node);
        result := TProcessItem.create(PO_SUCCESS, TProcessingXML.Create(node));
        paItem.Free;
      except
        on E:ENotValidPathsType do raise EPathsManager.Create(ePathManNotValidType);
        on E:EPathsManager do result := TProcessItem.create(PO_FAILURE,nil);
      end;
    end;
    PO_PATHS_GET_PATH_NAMES : begin
      strings := TStringList.Create;
      for path in aPaths do
        strings.Add(path.Name);
      Result := TProcessItem.create(PO_SUCCESS, TProcessingStrings.Create(strings));
    end;
    PO_PATHS_LOAD:
    begin
      try
        if not(paItem.Data is TProcessingXML) then raise ENotValidPathsType.Create(ePathManNotValidType);
        node := ((paItem.Data) as TProcessingXML).Node;
        Load(node);
        result := TProcessItem.create(PO_SUCCESS, TProcessingXML.Create(node));
        paItem.Free;
      except
        on E:ENotValidPathsType do raise EPathsManager.Create(ePathManNotValidType);
        on E:EPathsManager do result := TProcessItem.create(PO_FAILURE,nil);
      end;
    end;
    PO_EDITOR_PATHS_CANCEL : begin
      Load((aMaster.ProcessObject(TProcessItem.create(PO_PROJECT_LOAD_PATHS, NIL)).Data AS TProcessingXML).Node);
    end;
    PO_PATHS_GET_PATH:
    begin
      try
        if not(paItem.Data is TString) then raise ENotValidPathsType.Create(ePathManNotValidType);
        path := search((paItem.Data As TString).String_);
        if path <> nil then
          Result := TProcessItem.create(PO_SUCCESS,TProcessingPath.create(path))
        else
          Result := TProcessItem.create(PO_FAILURE,nil);
      except
        Result := TProcessItem.create(PO_FAILURE,nil);
      end;
    end;

  end; //Case
end;

procedure TPathsManager.resetList;
var
  Path: TPathType;
begin
  for Path in aPaths do Path.Free;
  aPaths.Free;
  aPaths := TList<TPathType>.Create;
end;

procedure TPathsManager.Save(var paWhere: IXMLNode);
var PathsTypeNode: IXMLNode;
  Path : TPathType;
begin
  PathsTypeNode := paWhere.AddChild('Paths');
//  PathsTypeNode.Attributes['name'] := Name;
  PathsTypeNode.Attributes['length'] := aPaths.Count;
  for Path in aPaths  do
  begin
    Path.Save(PathsTypeNode);
  end;
end;

procedure TPathsManager.Load(paFrom: IXMLNode);
var PathsTypeNode, PathTypeNode: IXMLNode;
  length, i: integer;
  Path : TPathType;
begin
  resetList;
  PathsTypeNode := paFrom;
  length := 2;
  // kvoli genialnemu tagu data v subore ktore si moje kody musia 27 zmyslom zistit asi sami ked si ho tam niekdo sam od seba prida ...
  PathsTypeNode :=  PathsTypeNode.ChildNodes.First;
  if Assigned(PathsTypeNode) then
  begin
    if PathsTypeNode.HasAttribute('length') then length := PathsTypeNode.Attributes['length'];
    PathTypeNode :=  PathsTypeNode.ChildNodes.First;
    for i := 0 to length - 1 do
    begin
      Path := TPathType.Create('', aMaster);
      Path.Load(PathTypeNode);
      aPaths.Add(Path);
      PathTypeNode := PathTypeNode.NextSibling;
    end;
  end;
end;


function TPathsManager.search(paName: String): TPathType;
var
  path: TPathType;
begin
  for path in Paths do
    if path.Name = paName then
    begin
      //we found it, let's return it and exit function
      result := path;
      exit;
    end;
  result := nil;
end;

{ TPedestrianManager.TPedestrianType }

constructor TPathsManager.TPathType.Create(paName: String; paMaster: TManager);
begin
  aName := paName;
  aMaster := paMaster;
  aWayPoints := Tlist<TEntity>.Create;
  aWayMatrixes := TList<fMatrix>.Create;
end;

destructor TPathsManager.TPathType.Destroy;
begin
  aWayPoints.Free;
  inherited;
end;

function TPathsManager.TPathType.Insert(paNew, paBefore: TEntity): Boolean;
var
  position : Integer;
begin
  Result := True;
  if Assigned(paBefore) then
  begin
    position := aWayPoints.IndexOf(paBefore as TEntity);
    aWayPoints.Insert(position, paNew);
  end
  else
    aWayPoints.Add(paNew);
end;

procedure TPathsManager.TPathType.Load(paFrom: IXMLNode);
var PathTypeNode, PointTypeNode: IXMLNode;
  length, i, id: integer;
  ret: TProcessItem;
begin
  resetList;
  PathTypeNode := paFrom;
  length := 0;
  if PathTypeNode.HasAttribute('name') then aName := PathTypeNode.Attributes['name'];
  if PathTypeNode.HasAttribute('name') then length := PathTypeNode.Attributes['length'];
  PointTypeNode :=  PathTypeNode.ChildNodes.First;
  for i := 0 to length - 1 do
  begin
    if PointTypeNode.HasAttribute('id') then
    begin
      id := PointTypeNode.Attributes['id'];
      ret := aMaster.ProcessObject(TProcessItem.create(PO_SCENE_GET_ENTITY_BY_ID,TInteger.Create(id))) ;
      aWayPoints.Add((ret.Data as TEntityProcessing).Entity_);
      PointTypeNode := PointTypeNode.NextSibling;
    end
    else
      raise EPathNotExists(ePathManEntityNotFound);
  end;
end;

function TPathsManager.TPathType.Remove(paRemove: TEntity): Boolean;
begin
  result := true;
  aWayPoints.Remove(paRemove);
end;

procedure TPathsManager.TPathType.resetList;
//var
  //point: TEntity;
begin
  //for point in aWayPoints do point.Free;
  aWayPoints.Free;
  aWayPoints := TList<TEntity>.Create;
end;

procedure TPathsManager.TPathType.Save(paWhere: IXMLNode);
var PathTypeNode, PointTypeNode: IXMLNode;
  Entity : TEntity;
begin
  PathTypeNode := paWhere.AddChild('Path');
  PathTypeNode.Attributes['name'] := Name;
  PathTypeNode.Attributes['length'] := aWayPoints.Count;
  for Entity in aWayPoints do
  begin
    PointTypeNode := PathTypeNode.AddChild('Point');
    PointTypeNode.Attributes['id'] := Entity.Id;
  end;
end;

end.
